// Copyright (c) Appeon. All rights reserved.
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.

using System;
using System.Collections.Generic;
using System.Linq;

namespace SnapObjects.Data
{
    /// <summary>
    ///     Represents an object that can unpack a data package which contains multiple types of data.
    ///     The data package must conform to the specified format.
    /// </summary>
    public class DataUnpacker : IDataUnpacker
    {
        private readonly IDictionary<string, string> _raws;

        /// <summary>
        ///     Initializes a new instance of the DataUnpacker class.
        /// </summary>
        /// <param name="raw">
        ///     A raw string which contains the data package.
        ///     The format of the data package must conform to the specified format.
        /// </param>
        /// <param name="format">
        ///     An enumerate value of the DataFormat enumeration.
        ///     It only supports DataFormat.Json so far.
        ///</param>
        public DataUnpacker(string raw, DataFormat format)
        {
            this.Raw = raw;
            this.DataFormat = format;

            _raws = this.Init(raw, format);
        }

        /// <summary>
        ///     Gets the format of the text specified when creating the IDataUnpacker object.
        /// </summary>
        public DataFormat DataFormat { get; }

        /// <summary>
        ///     Gets the raw string of text which contains all of the elements in the IDataUnpacker object.
        /// </summary>
        public string Raw { get; }

        /// <summary>
        ///     Gets the number of elements added in the IDataUnpacker object.
        /// </summary>
        public int Count => _raws.Count;

        /// <summary>
        ///     Gets the keys of all of the elements in the IDataUnpacker object.
        /// </summary>
        public string[] Keys => _raws.Keys.ToArray();

        /// <summary>
        ///     Checks whether the specified key exists in the IDataUnpacker object.
        /// </summary>
        /// <param name="key">The key of the element to look for.</param>
        /// <returns>Returns true if the element exists; otherwise, false.</returns>
        public bool ContainsKey(string key)
        {
            return _raws.ContainsKey(key);
        }

        /// <summary>
        ///     Gets the raw string of text for the specified element.
        /// </summary>
        /// <param name="key">The key specifying which element to get the raw string of text.</param>
        /// <returns>Returns the raw string of text for the element if the key exists; otherwise, returns String.Empty.</returns>
        public string GetRaw(string key)
        {
            if (_raws.ContainsKey(key))
            {
                return _raws[key];
            }
            else
            {
                return String.Empty;
            }
        }

        /// <summary>
        ///     Removes the element from the IDataUnpacker object according to the specified key.
        /// </summary>
        /// <param name="key">The key of the element to remove.</param>
        /// <returns>Returns true if the element is successfully removed; returns false if the key was not found.</returns>
        public bool RemoveKey(string key)
        {
            return _raws.Remove(key);
        }

        private IDictionary<string, string> Init(string raw, DataFormat format)
        {
            var reader = DataFormaterFactory.GetDataReader(raw, format);

            var datas = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);

            if (reader.Read())
            {
                while (!reader.IsEnd)
                {
                    var value = reader.ReadAsRaw();

                    datas.Add(value.Name, value.ToString());
                }
            }

            return datas;
        }
    }
}
